/*
 * Debts Manager. Simple android application for managing debts.
 * Copyright (C) 2010 Maxim Manuylov
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
 */

package manuylov.maxim.dm.activity;

import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.*;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.inputmethod.EditorInfo;
import android.widget.*;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import manuylov.maxim.dm.Constants;
import manuylov.maxim.dm.R;
import manuylov.maxim.dm.data.DataManager;
import manuylov.maxim.dm.data.object.Debt;
import manuylov.maxim.dm.data.object.DebtsListItem;
import manuylov.maxim.dm.data.object.PartialPayment;
import manuylov.maxim.dm.data.util.DataActionResultProcessor;
import manuylov.maxim.dm.data.util.DataProcessor;
import manuylov.maxim.dm.data.util.DataUtil;

import java.util.Date;
import java.util.List;

public class BalanceByPerson extends BaseBalanceActivity {
    private int myPersonId;
    private ListView myBalanceList;
    private Debt mySelectedDebt;

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.balance_by_person);

        final Intent intent = getIntent();
        setTitle(getStringOrFinish(intent, Constants.PERSON_NAME));

        myBalanceList = (ListView) findViewById(R.id.balance_list);
        myBalanceList.setEmptyView(findViewById(R.id.empty_list_view));

        myPersonId = getIntOrFinish(intent, Constants.PERSON_ID);

        reloadData();

        registerForContextMenu(myBalanceList);

        myBalanceList.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
                final View additionalText = view.findViewById(R.id.additional_text);
                additionalText.setVisibility(additionalText.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
            }
        });
    }

    @Override
    protected void reloadData() {
        DataUtil.perfromDataAction(this, R.string.loading, new DataProcessor<List<DebtsListItem>>() {
            public List<DebtsListItem> process(final DataManager dataManager) {
                return dataManager.getDebtsByPerson(myPersonId, myBalanceMode);
            }
        }, new DataActionResultProcessor<List<DebtsListItem>>() {
            public Void process(final List<DebtsListItem> debts) {
                if (debts.size() == 0) {
                    finish();
                }
                final ListAdapter adapter = new BalanceByPersonListAdapter(BalanceByPerson.this, debts);
                myBalanceList.setAdapter(adapter);
                return null;
            }
        });
    }

    @Override
    public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        final AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
        final DebtsListItem selectedItem = (DebtsListItem) myBalanceList.getAdapter().getItem(adapterMenuInfo.position);
        if (selectedItem.isSummaryItem()) {
            menu.close();
            return;
        }
        mySelectedDebt = (Debt) selectedItem;
        final MenuInflater inflater = getMenuInflater();
        if (myBalanceMode == Constants.BALANCE_MODE_ACTUAL) {
            inflater.inflate(R.menu.debt_context_menu_actual_mode, menu);
        } else if (myBalanceMode == Constants.BALANCE_MODE_HISTORY) {
            inflater.inflate(R.menu.debt_context_menu_history_mode, menu);
        }
        menu.setHeaderTitle(R.string.choose_action_for_this_debt);
    }

    @Override
    public boolean onContextItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
            case R.id.edit_comment_menu_item: {
                showDialog(Constants.DIALOG_COMMENT);
                return true;
            }

            case R.id.pay_menu_item:
            case R.id.remove_menu_item: {
                DataUtil.perfromDataAction(this, R.string.updating, new DataProcessor<Void>() {
                    public Void process(final DataManager dataManager) {
                        dataManager.removeDebt(mySelectedDebt, myBalanceMode);
                        return null;
                    }
                }, new DataActionResultProcessor<Void>() {
                    public Void process(final Void v) {
                        showShortToast(R.string.the_debt_was_successfully_removed);
                        chainReload();
                        return null;
                    }
                });
                return true;
            }

            case R.id.pay_partly_menu_item: {
                showDialog(Constants.DIALOG_QUANTITY);
                return true;
            }
        }
        return super.onContextItemSelected(item);
    }

    private void chainReload() {
        setResult(Constants.RESULT_NEED_TO_RELOAD_DATA);
        reloadData();
    }

    @Override
    protected void onPrepareDialog(final int dialogId, final Dialog dialog) {
        switch (dialogId) {
            case Constants.DIALOG_QUANTITY: {
                final EditText quantityEditor = (EditText) dialog.findViewById(R.id.quantity_editor);
                quantityEditor.setInputType(EditorInfo.TYPE_CLASS_NUMBER);
                quantityEditor.setText("");
                return;
            }
            case Constants.DIALOG_COMMENT: {
                final EditText commentEditor = (EditText) dialog.findViewById(R.id.comment_editor);
                commentEditor.setText(mySelectedDebt.getComment());
                return;
            }
        }
        super.onPrepareDialog(dialogId, dialog);
    }

    @Override
    protected Dialog onCreateDialog(final int dialogId) {
        switch (dialogId) {
            case Constants.DIALOG_QUANTITY: {
                return doCreateDialog(R.layout.quantity_dialog, R.string.type_quantity, new DialogProcessor() {
                    public Void process(final Dialog dialog) {
                        final String quantityStr = getTrimmedEditorText(dialog, R.id.quantity_editor);
                        if (quantityStr.length() == 0) {
                            showShortToast(R.string.quantity_must_not_be_empty);
                            focus(dialog, R.id.quantity_editor);
                            return null;
                        }

                        final Integer quantity = parseInteger(quantityStr);
                        if (quantity == null) {
                            showShortToast(R.string.is_not_a_number, quantityStr);
                            focus(dialog, R.id.quantity_editor);
                            return null;
                        }

                        if (quantity < 0) {
                            showShortToast(R.string.quantity_must_not_be_less_than_zero);
                            focus(dialog, R.id.quantity_editor);
                            return null;
                        }

                        if (quantity == 0) {
                            showShortToast(R.string.quantity_must_not_be_equal_to_zero);
                            focus(dialog, R.id.quantity_editor);
                            return null;
                        }

                        final int remainder = mySelectedDebt.getRemainder();

                        if (quantity > remainder) {
                            showShortToast(R.string.quantity_must_not_be_greater_than_debt_remainder);
                            focus(dialog, R.id.quantity_editor);
                            return null;
                        }

                        final boolean isFullRemainder = quantity == remainder;

                        DataUtil.perfromDataAction(BalanceByPerson.this, R.string.updating, new DataProcessor<Void>() {
                            public Void process(final DataManager dataManager) {
                                if (isFullRemainder) {
                                    dataManager.removeDebt(mySelectedDebt, myBalanceMode);
                                } else {
                                    dataManager.addPartialPayment(mySelectedDebt.getId(), quantity);
                                }
                                return null;
                            }
                        }, new DataActionResultProcessor<Void>() {
                            public Void process(final Void v) {
                                showShortToast(isFullRemainder ? R.string.the_debt_was_successfully_removed : R.string.the_debt_was_successfully_updated);
                                chainReload();
                                return null;
                            }
                        });

                        dialog.dismiss();
                        return null;
                    }
                });
            }
            case Constants.DIALOG_COMMENT: {
                return doCreateDialog(R.layout.comment_dialog, R.string.edit_comment_title, new DialogProcessor() {
                    public Void process(final Dialog dialog) {
                        final String comment = getTrimmedEditorText(dialog, R.id.comment_editor);

                        DataUtil.perfromDataAction(BalanceByPerson.this, R.string.updating, new DataProcessor<Void>() {
                            public Void process(final DataManager dataManager) {
                                dataManager.updateComment(mySelectedDebt.getId(), comment, myBalanceMode);
                                return null;
                            }
                        }, new DataActionResultProcessor<Void>() {
                            public Void process(final Void v) {
                                showShortToast(R.string.the_debt_was_successfully_updated);
                                chainReload();
                                return null;
                            }
                        });

                        dialog.dismiss();
                        return null;
                    }
                });
            }
        }
        return super.onCreateDialog(dialogId);
    }

    private static class BalanceByPersonListAdapter extends ArrayAdapter<DebtsListItem> {
        private final java.text.DateFormat myDateFormat;
        private final java.text.DateFormat myTimeFormat;
        private final Resources myResources;

        private final static String LINE_TERMINATOR = "\n";

        public BalanceByPersonListAdapter(final Context context, final List<DebtsListItem> debts) {
            super(context, R.layout.debt, R.id.title_text, debts);
            myDateFormat = DateFormat.getLongDateFormat(context);
            myTimeFormat = DateFormat.getTimeFormat(context);
            myResources = context.getResources();
        }

        @Override
        public boolean isEnabled(final int position) {
            return !getItem(position).isSummaryItem();
        }

        @Override
        public long getItemId(final int position) {
            return getItem(position).getId();
        }

        @Override
        public int getItemViewType(int position) {
            return getItem(position).isSummaryItem() ? 1 : 0;
        }

        @Override
        public int getViewTypeCount() {
            return 2;
        }

        @Override
        public View getView(final int position, final View convertView, final ViewGroup parent) {
            final View view = super.getView(position, convertView, parent);
            final DebtsListItem debtsListItem = getItem(position);

            if (debtsListItem.isSummaryItem()) {
                view.findViewById(R.id.title_text).setVisibility(View.GONE);
                view.findViewById(R.id.total).setVisibility(View.VISIBLE);
                final TextView totalText = (TextView) view.findViewById(R.id.total_text);
                totalText.setVisibility(View.VISIBLE);
                totalText.setText(debtsListItem.toString());
                int textColor;
                switch (debtsListItem.getRecordType()) {
                    case Constants.LEND: {
                        textColor = Color.GREEN;
                        break;
                    }
                    case Constants.BORROW: {
                        textColor = Color.RED;
                        break;
                    }
                    default: {
                        textColor = Color.YELLOW;
                        break;
                    }
                }
                totalText.setTextColor(textColor);
                view.setLongClickable(false);
                return view;
            }

            final Debt debt = (Debt) debtsListItem;

            final boolean isLendDebt = debt.getRecordType() == Constants.LEND;

            final TextView titleTextView = (TextView) view.findViewById(R.id.title_text);
            titleTextView.setTextColor(isLendDebt ? Color.GREEN : Color.RED);

            final String debtSign = isLendDebt ? "+" : "-";
            final StringBuilder text = new StringBuilder("");

            final String comment = debt.getComment();
            if (comment.length() != 0) {
                text.append(getString(R.string.comment));
                text.append(LINE_TERMINATOR);
                text.append(comment);
                text.append(LINE_TERMINATOR);
                text.append(LINE_TERMINATOR);
            }

            text.append(getString(R.string.history));
            appendDate(text, debt.getDate());
            text.append(getString(R.string.debt_was_created));

            int debtRemainder = debt.getQuantity();

            final List<PartialPayment> partialPayments = debt.getPartialPayments();
            if (partialPayments.size() > 0) {
                appendRemainder(text, debtSign, debtRemainder);
            }
            for (final PartialPayment partialPayment : partialPayments) {
                final int partialPaymentQuantity = partialPayment.getQuantity();
                debtRemainder -= partialPaymentQuantity;
                appendDate(text, partialPayment.getDate());
                if (debtRemainder > 0) {
                    text.append(getString(R.string.debt_was_partially_paid));
                    text.append(partialPaymentQuantity);
                    appendRemainder(text, debtSign, debtRemainder);
                } else {
                    text.append(getString(R.string.debt_was_fully_paid));
                    text.append(partialPaymentQuantity);
                }
            }

            ((TextView) view.findViewById(R.id.additional_text)).setText(text.toString());
            return view;
        }

        private void appendRemainder(final StringBuilder text, final String debtSign, final int debtRemainder) {
            text.append(LINE_TERMINATOR);
            text.append(getString(R.string.remainder));
            text.append(debtSign);
            text.append(debtRemainder);
        }

        private void appendDate(final StringBuilder sb, final Date date) {
            sb.append(LINE_TERMINATOR);
            sb.append(LINE_TERMINATOR);
            sb.append(myDateFormat.format(date));
            sb.append(" ");
            sb.append(myTimeFormat.format(date));
            sb.append(LINE_TERMINATOR);
        }

        private String getString(final int resId) {
            return myResources.getString(resId);
        }
    }
}
